﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Autofac;
using DotNet.Utilities.ConsoleHelper;
using HproseRpcTester.RpcClient;
using HproseRpcTester.Utils;
using PropertyChanged;
using WPFPractice.Utils;
using WPFTemplateLib.WpfHelpers;

namespace HproseRpcTester
{
    public partial class WinHproseTester : Window
    {
        private HproseTesterViewModel _vm;

        public WinHproseTester()
        {
            InitializeComponent();
            DataContext = _vm = new HproseTesterViewModel();
        }
    }

    [AddINotifyPropertyChangedInterface]
    public class HproseTesterViewModel : MyBindableBase
    {
        #region 成员

        private IRunRPCEx _runRpcEx;

        #endregion

        #region Bindable

        /// <summary>
        /// 循环次数
        /// </summary>
        public long LoopCount { get; set; } = 1000;

        #endregion

        #region Command

        /// <summary>
        /// 同步调用带 async 和 Task.Run 的方法
        /// </summary>
        public ICommand SyncAsyncTaskCmd { get; set; }

        /// <summary>
        /// 异步调用带 async 和 Task.Run 的方法
        /// </summary>
        public ICommand AsyncAsyncTaskCmd { get; set; }

        /// <summary>
        /// 同步调用不带 async 带 Task.Run 的方法
        /// </summary>
        public ICommand SyncSyncTaskCmd { get; set; }

        /// <summary>
        /// 异步调用不带 async 带 Task.Run 的方法
        /// </summary>
        public ICommand AsyncSyncTaskCmd { get; set; }

        /// <summary>
        /// 同步调用带 async 不带 Task.Run 的方法
        /// </summary>
        public ICommand SyncAsyncCmd { get; set; }

        /// <summary>
        /// 异步调用带 async 不带 Task.Run 的方法
        /// </summary>
        public ICommand AsyncAsyncCmd { get; set; }

        /// <summary>
        /// 同步调用不带 async 不带 Task.Run 的方法
        /// </summary>
        public ICommand SyncSyncCmd { get; set; }

        /// <summary>
        /// 异步调用不带 async 不带 Task.Run 的方法
        /// </summary>
        public ICommand AsyncSyncCmd { get; set; }

        #endregion

        public HproseTesterViewModel()
        {
            Console.SetOut(new ConsoleWriter(ShowInfo));
            InitValue();

            StartIoc();

            SetCommandMethod();
        }

        /// <summary>
        /// 配置容器相关
        /// </summary>
        private static void StartIoc()
        {
            AutofacHelper.StartDI()
                .RegisterScope(typeof(RunRPCEx))
                .AutofacDependencyInjection(new Dictionary<string, string>
                {
                    {nameof(HproseRpcTester), "RPCService"}
                }, DependencyInjectionType.Singleton)
                .AddRPCService()
                .EndDI()
                .UseRPC(AppConsts.RPCPort);
        }

        /// <summary>
        /// 数据初始化
        /// </summary>
        private void InitValue()
        {
            ShowInfo("测试 Hprose RPC 框架");
        }

        /// <summary>
        /// 命令方法赋值(在构造函数中调用)
        /// </summary>
        private void SetCommandMethod()
        {
            _runRpcEx = AutofacHelper.Container?.Resolve<IRunRPCEx>();

            SyncAsyncTaskCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(1, "同步调用带 async 和 Task.Run 的方法", () =>
                {
                    string result = _runRpcEx?.SyncAsyncTask();
                    Console.WriteLine($"{result}");
                });
            });

            AsyncAsyncTaskCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(2, "异步调用带 async 和 Task.Run 的方法", async () =>
                {
                    string result = await _runRpcEx?.AsyncAsyncTask();
                    Console.WriteLine($"{result}");
                });
            });

            SyncSyncTaskCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(3, "同步调用不带 async 带 Task.Run 的方法", async () =>
                {
                    string result = _runRpcEx?.SyncSyncTask();
                    Console.WriteLine($"{result}");
                });
            });

            AsyncSyncTaskCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(4, "异步调用不带 async 带 Task.Run 的方法", async () =>
                {
                    string result = await _runRpcEx?.AsyncSyncTask();
                    Console.WriteLine($"{result}");
                });
            });

            SyncAsyncCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(5, "同步调用带 async 不带 Task.Run 的方法", async () =>
                {
                    string result = _runRpcEx?.SyncAsync();
                    Console.WriteLine($"{result}");
                });
            });

            AsyncAsyncCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(6, "异步调用带 async 不带 Task.Run 的方法", async () =>
                {
                    string result = await _runRpcEx?.AsyncAsync();
                    Console.WriteLine($"{result}");
                });
            });

            SyncSyncCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(7, "同步调用不带 async 不带 Task.Run 的方法", async () =>
                {
                    string result = _runRpcEx?.SyncSync();
                    Console.WriteLine($"{result}");
                });
            });

            AsyncSyncCmd ??= new RelayCommand(o => true, async o =>
            {
                await TestMethod(8, "异步调用不带 async 不带 Task.Run 的方法", async () =>
                {
                    string result = await _runRpcEx?.AsyncSync();
                    Console.WriteLine($"{result}");
                });
            });
        }

        /// <summary>
        /// 测试方法模板
        /// </summary>
        private async Task TestMethod(int num, string name, Action method)
        {
            Console.WriteLine("===========================================================================");
            Console.WriteLine($"{num}、{name}");

            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < LoopCount; i++)
            {
                await Task.Run(() =>
                {
                    try
                    {
                        method.Invoke();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"{num}-{i} 异常：{ex}");
                    }
                });
            }

            sw.Stop();
            Console.WriteLine($"{num}、{name}：耗时：{sw.Elapsed.TotalSeconds} s");
        }
    }
}
